package com.rarebot.script.methods;

import com.rarebot.script.methods.Game.Tab;
import com.rarebot.script.wrappers.RSComponent;
import com.rarebot.script.wrappers.RSInterface;
import com.rarebot.script.wrappers.RSItem;

/**
 * Equipment related operations.
 */
public class Equipment extends MethodProvider {
	public static final int INTERFACE_EQUIPMENT = Tab.EQUIPMENT.interfaceID();
	public static final int ITEM_SLOTS = 12;
	public static final int HELMET = 6;
    public static final int CAPE = 9;
    public static final int NECK = 12;
    public static final int WEAPON = 15;
    public static final int BODY = 18;
    public static final int SHIELD = 21;
    public static final int LEGS = 24;
    public static final int HANDS = 27;
    public static final int FEET = 30;
    public static final int RING = 33;
    public static final int AMMO = 36;
    public static final int AURA = 43;

	Equipment(final MethodContext ctx) {
		super(ctx);
	}

	/**
	 * Gets the equipment interface.
	 *
	 * @return the equipment interface
	 */
	public RSInterface getInterface() {
		if (methods.game.getTab() != Tab.EQUIPMENT) {
			if (methods.bank.isOpen()) {
				methods.bank.close();
			}
			methods.game.openTab(Tab.EQUIPMENT);
			sleep(random(900, 1500));
		}
		return methods.interfaces.get(INTERFACE_EQUIPMENT);
	}

  /**
	 * Opens the game tab relating to this utility.
	 *
	 * @return <tt>true</tt> if the tab was opened, otherwise <tt>false</tt>.
	 */
	public boolean openTab() {
		final Tab tab = Tab.EQUIPMENT;
		return methods.bank.isOpen() || methods.game.getTab() == tab || methods.game.openTab(tab, true);
	}
  
	/**
	 * Gets the equipment array.
	 *
	 * @return An array containing all equipped items
	 */
	public RSItem[] getItems() {
		final RSComponent[] equip = getInterface().getComponents();
		final RSItem[] items = new RSItem[ITEM_SLOTS];
		for (int i = 0; i < items.length; i++) {
			items[i] = new RSItem(methods, equip[i * 3 + 9]);
		}
		return items;
	}

	/**
	 * Gets the worn equipment array.
	 * This method excludes stack sizes.
	 *
	 * @return An array containing all equipped items
	 */
	public RSItem[] getWornItems() {
		final int[] equip = methods.players.getMyPlayer().getEquipment();
		final RSItem[] items = new RSItem[ITEM_SLOTS];
		for (int i = 0; i < items.length; i++) {
			items[i] = new RSItem(methods, equip[i], 1);
		}
		return items;
	}

	/**
	 * Gets the cached equipment array (i.e. does not open the interface).
	 *
	 * @return The items equipped as seen when the equipment tab was last
	 *         opened.
	 */
	public RSItem[] getCachedItems() {
		final RSInterface equipment = methods.interfaces.get(INTERFACE_EQUIPMENT);
		final RSComponent[] components = equipment.getComponents();
		final RSItem[] items = new RSItem[ITEM_SLOTS];
		for (int i = 0; i < items.length; i++) {
			items[i] = new RSItem(methods, components[i * 3 + 9]);
		}
		return items;
	}

	/**
	 * Gets the equipment item at a given index.
	 *
	 * @param index The item index.
	 * @return The equipped item.
	 */
	public RSItem getItem(final int index) {
		return new RSItem(methods, getInterface().getComponents()[index]);
	}
   
   /**
	 * Gets the first item in the inventory with an id matching the argument(s)
	 *
	 * @param itemIds The id(s) to search for
	 * @return An <code>Item</code> with an id matching the argument(s).
	 */
	public RSItem getItem(final int... itemIds) {
		if (!openTab()) {
			return null;
		}
		for (final RSItem item : getItems()) {
			if (item == null) {
				continue;
			}
			for (final int itemId : itemIds) {
				if (itemId == item.getID()) {
					return item;
				}
			}
		}
		return null;
	}


  /**
	 * Gets the count of all equipped items matching with any of the provided ids ignoring stack sizes.
	 *
	 * @param itemIds The item ids to look for.
	 * @return The count of the items matching the item ids.
	 */
	public int getCount(final int... itemIds) {
		int count = 0;
		if (!openTab()) {
			return count;
		}
		for (final RSItem item : getItems()) {
			if (item == null) {
				continue;
			}
			final int itemId = item.getID();
			for (final int id : itemIds) {
				if (itemId == id) {
					count++;
					break;
				}
			}
		}
		return count;
	}

	/**
	 * Returns the number of items equipped excluding stack sizes.
	 *
	 * @return Amount of items currently equipped.
	 */
	public int getCount() {
		return ITEM_SLOTS - getCount(-1);
	}

	/**
	 * Returns the number of items matching a given ID equipped excluding stack
	 * sizes.
	 *
	 * @param itemID The item ID to count. Same as the equipment/item id in the
	 *               inventory.
	 * @return Amount of specified item currently equipped.
	 * @see #getItems()
	 */
	public int getCount(final int itemID) {
		int count = 0;
		for (final RSItem item : getItems()) {
			if (item.getID() == itemID) {
				count++;
			}
		}
		return count;
	}

	/**
	 * Checks whether the player has all of the given items equipped.
	 *
	 * @param items The item ID to check for. Same as the equipment/item id in the
	 *              inventory.
	 * @return <tt>true</tt> if specified item is currently equipped; otherwise
	 *         <tt>false</tt>.
	 * @see #getItems()
	 */
	public boolean containsAll(final int... items) {
		final RSItem[] equips = getItems();
		int count = 0;
		for (final int item : items) {
			for (final RSItem equip : equips) {
				if (equip.getID() == item) {
					count++;
					break;
				}
			}
		}
		return count == items.length;
	}

	/**
	 * Checks if the player has one (or more) of the given items equipped.
	 *
	 * @param items The IDs of items to check for.
	 * @return <tt>true</tt> if the player has one (or more) of the given items
	 *         equipped; otherwise <tt>false</tt>.
	 */
	public boolean containsOneOf(final int... itemIds) {
		if (!openTab()) {
			return false;
		}
		for (final RSItem item : getItems()) {
			final int itemId = item.getID();
			for (final int id : itemIds) {
				if (itemId == id) {
					return true;
				}
			}
		}
		return false;
	}
   
  /**
	 * Unequips an item if it is present in the current equipment
	 *
	 * @param itemIds The ids of the item(s) that need(s) to be unequipped.
	 * @return <tt>true</tt> if an item was successfully unequipped; otherwise <tt>false</tt>.
	 */
	public boolean unequip(final int... itemIds) {
		if (!openTab()) {
			return false;
		}
		final int count = getCount(itemIds);
		final RSItem item = getItem(itemIds);
		if (item != null) {
			if (item.interact("Remove")) {
				sleep(random(250, 500));
				return getCount(itemIds) < count;
			}
		}
		return false;
	}
}
